
#include <sys/wait.h>
#include <sys/types.h>
#include <iostream>
#include <cerrno>
#include <unistd.h>
#include "ProcessPool.h"

namespace ZMH
{
    size_t process_pool::process_size()
    {
        return _pm.size();
    }

    size_t process_pool::task_size()
    {
        return _tm.size();
    }

    void process_pool::close_all_pipeW()
    {
        for (auto x : _pm)
            close(x._fd);
    }

    size_t process_pool::send(int code)
    {
        // 被选择的孩子进程
        const int &ret_cnt = _cnt++;
        _cnt %= process_size();
        auto child_process = _pm[ret_cnt];
        // 对该进程发送任务码
        int ret = write(child_process._fd, &code, sizeof(code));
        if (ret == sizeof(code))
            return ret_cnt;
        else
            return -1;
    }

    void process_pool::execut()
    {
        while (true)
        {
            int code = 0;
            int ret = read(3, &code, sizeof(code));
            if (ret == 0)
                break;
            else if (ret != sizeof(code))
                continue;
            printf("子进程:%d,开始执行%d任务...\n", getpid(), code);
            _tm[code]();
        }
    }

    process_pool::process_pool(size_t cnt, std::vector<std::function<void()>> tm) : _tm(tm), _cnt(0)
    {
        for (int i = 0; i < cnt; i++)
        {
            int pipefd[2] = {0};
            int flag = pipe(pipefd);
            if (flag == -1)
            {
                std::cerr << "父进程打开管道文件失败，错误码是:" << errno << std::endl;
                break; // 不用玩了，直接 say to bye
            }
            pid_t pid = fork(); // 父子进程开始有相同的数据__pm,_tm,文件描述符表
            if (pid == -1)
            {
                std::cerr << "父进程创建子进程失败，错误码是:" << errno << std::endl;
                break; // 不用玩了，直接 say to bye
            }
            else if (pid == 0)
            {
                // step1 - 关闭不需要的管道操作 + 哥哥进程对应的管道w端
                close_all_pipeW();
                close(pipefd[1]);
                // step2 - 进程处于工作状态
                execut();
                // step3 - 进程结束
                exit(0);
            }
            // step1 - 关闭不需要的管道操作
            close(pipefd[0]);
            // step2 - 将子进程与对应的管道组织管理起来
            _pm.emplace_back(pipefd[1], pid);
        }
    }

    process_pool::~process_pool()
    {
        // 1. 将父进程的所有写管道全部关闭 - 子进程read返回值为0，则会退出break循环，执行exit退出进程
        // 2. 等待所有子进程
        // 3. 管道文件引用计数为0自动回收
        // 至于容器，会自动调用他们对应的析构函数的。
        for (auto childprocess : _pm)
        {
            printf("正在回收子进程:%d...\n", childprocess._pid);
            close(childprocess._fd);
            waitpid(childprocess._pid, nullptr, 0);
            sleep(1);
        }
        // for(int i = _pm.size() -1;i >= 0;i--)
        // {
        //     printf("正在回收子进程:%d...\n", _pm[i]._pid);
        //     close( _pm[i]._fd);
        //     waitpid(_pm[i]._pid,nullptr,0);
        //     sleep(1);
        // }
    }
}
